/**
 * MH-Z19B CO2传感器驱动
 * 使用UART串口通信
 */

#include "mhz19b.h"
#include "stdio.h"

// 使用USART3连接MH-Z19B (PB10=TX, PB11=RX)
#define MHZ19B_USART USART3
#define MHZ19B_BAUDRATE 9600

// 超时定义
#define MHZ19B_TIMEOUT 1000

// 私有函数声明
static void MHZ19B_USART_Init(void);
static uint8_t MHZ19B_CalculateChecksum(uint8_t *packet, uint8_t len);

// MH-Z19B初始化
void MHZ19B_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 使能GPIOB和USART3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    
    // 配置USART3 TX (PB10)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 配置USART3 RX (PB11)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // 初始化串口
    MHZ19B_USART_Init();
    
    // 延时等待传感器启动
    for (int i = 0; i < 1000000; i++); // 约1秒
    
    // 关闭自动校准
    MHZ19B_Set_AutoCalibration(0);
    
    printf("MH-Z19B CO2传感器初始化完成\r\n");
}

// USART3初始化
static void MHZ19B_USART_Init(void) {
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    // USART3配置
    USART_InitStructure.USART_BaudRate = MHZ19B_BAUDRATE;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(MHZ19B_USART, &USART_InitStructure);
    
    // 使能USART3
    USART_Cmd(MHZ19B_USART, ENABLE);
    
    // 配置USART3中断
    USART_ITConfig(MHZ19B_USART, USART_IT_RXNE, ENABLE);
    
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

// 计算校验和
static uint8_t MHZ19B_CalculateChecksum(uint8_t *packet, uint8_t len) {
    uint8_t checksum = 0;
    for (uint8_t i = 1; i < len - 1; i++) { // 从第2个字节开始，不包括校验和本身
        checksum += packet[i];
    }
    return 0xFF - checksum;
}

// 发送命令
uint8_t MHZ19B_Send_Command(uint8_t cmd, uint8_t *data, uint8_t len) {
    uint8_t packet[9];
    
    // 构建数据包
    packet[0] = 0xFF;  // 起始字节1
    packet[1] = 0x01;  // 起始字节2 (地址)
    packet[2] = cmd;   // 命令
    
    // 填充数据
    for (uint8_t i = 0; i < 5; i++) {
        if (i < len) {
            packet[3 + i] = data[i];
        } else {
            packet[3 + i] = 0x00;
        }
    }
    
    // 计算校验和
    packet[8] = MHZ19B_CalculateChecksum(packet, 9);
    
    // 发送数据包
    for (uint8_t i = 0; i < 9; i++) {
        while (USART_GetFlagStatus(MHZ19B_USART, USART_FLAG_TXE) == RESET);
        USART_SendData(MHZ19B_USART, packet[i]);
    }
    
    return 1;
}

// 接收响应
uint8_t MHZ19B_Receive_Response(MHZ19B_Packet *packet) {
    uint8_t buffer[9];
    uint32_t timeout = MHZ19B_TIMEOUT;
    
    // 等待接收9个字节
    for (uint8_t i = 0; i < 9; i++) {
        while (USART_GetFlagStatus(MHZ19B_USART, USART_FLAG_RXNE) == RESET) {
            if (--timeout == 0) {
                return 0; // 超时
            }
        }
        buffer[i] = USART_ReceiveData(MHZ19B_USART);
    }
    
    // 验证起始字节
    if (buffer[0] != 0xFF || buffer[1] != 0x01) {
        return 0;
    }
    
    // 验证校验和
    uint8_t checksum = MHZ19B_CalculateChecksum(buffer, 9);
    if (buffer[8] != checksum) {
        return 0;
    }
    
    // 复制数据到结构体
    packet->header[0] = buffer[0];
    packet->header[1] = buffer[1];
    packet->cmd = buffer[2];
    for (uint8_t i = 0; i < 5; i++) {
        packet->data[i] = buffer[3 + i];
    }
    packet->checksum = buffer[8];
    
    return 1;
}

// 读取CO2浓度
uint16_t MHZ19B_Read_CO2(void) {
    MHZ19B_Packet response;
    uint8_t cmd_data[5] = {0};
    
    // 发送读取CO2命令
    if (!MHZ19B_Send_Command(MHZ19B_CMD_READ_CO2, cmd_data, 0)) {
        return 0;
    }
    
    // 等待响应
    for (int i = 0; i < 10000; i++); // 短暂延时
    
    // 接收响应
    if (!MHZ19B_Receive_Response(&response)) {
        return 0;
    }
    
    // 解析CO2浓度 (高字节在前)
    uint16_t co2_ppm = (response.data[0] << 8) | response.data[1];
    
    printf("CO2浓度: %d ppm\r\n", co2_ppm);
    return co2_ppm;
}

// 读取温度
uint8_t MHZ19B_Read_Temperature(void) {
    MHZ19B_Packet response;
    uint8_t cmd_data[5] = {0};
    
    // 发送读取温度命令
    if (!MHZ19B_Send_Command(MHZ19B_CMD_READ_TEMP, cmd_data, 0)) {
        return 0;
    }
    
    // 等待响应
    for (int i = 0; i < 10000; i++); // 短暂延时
    
    // 接收响应
    if (!MHZ19B_Receive_Response(&response)) {
        return 0;
    }
    
    // 解析温度值
    uint8_t temp = response.data[0] - 40; // 温度补偿
    
    printf("温度: %d C\r\n", temp);
    return temp;
}

// 设置自动校准
uint8_t MHZ19B_Set_AutoCalibration(uint8_t enable) {
    MHZ19B_Packet response;
    uint8_t cmd_data[5] = {0};
    
    if (enable) {
        cmd_data[0] = 0xA0; // 开启自动校准
    } else {
        cmd_data[0] = 0x00; // 关闭自动校准
    }
    
    // 发送命令
    if (!MHZ19B_Send_Command(MHZ19B_CMD_AUTO_CALIBRATION, cmd_data, 1)) {
        return 0;
    }
    
    // 等待响应
    for (int i = 0; i < 10000; i++); // 短暂延时
    
    // 接收响应
    if (!MHZ19B_Receive_Response(&response)) {
        return 0;
    }
    
    printf("自动校准%s\r\n", enable ? "开启" : "关闭");
    return 1;
}

// 零点校准
uint8_t MHZ19B_Calibrate_Zero(void) {
    MHZ19B_Packet response;
    uint8_t cmd_data[5] = {0};
    
    // 发送零点校准命令
    if (!MHZ19B_Send_Command(MHZ19B_CMD_CALIBRATE_ZERO, cmd_data, 0)) {
        return 0;
    }
    
    // 等待响应
    for (int i = 0; i < 10000; i++); // 短暂延时
    
    // 接收响应
    if (!MHZ19B_Receive_Response(&response)) {
        return 0;
    }
    
    printf("零点校准完成\r\n");
    return 1;
}

// USART3中断服务函数
void USART3_IRQHandler(void) {
    if (USART_GetITStatus(MHZ19B_USART, USART_IT_RXNE) != RESET) {
        // 接收中断处理 (如果需要的话)
        uint8_t data = USART_ReceiveData(MHZ19B_USART);
        // 这里可以添加接收缓冲区管理
        USART_ClearITPendingBit(MHZ19B_USART, USART_IT_RXNE);
    }
}
